using System;
using System.Web.UI;
using System.Collections;
using System.Collections.Specialized;

namespace Edge.Common.DataUtils
{
    /// <summary>
    /// Fasade
    /// </summary>
    public delegate object GetPropertyValue(object src);
    public delegate void SetPropertyValue(object obj, object value);

    public interface IPropertyValueGetter
    {
        object Get(object source);
    }

    public interface IPropertyValueSetter
    {
        void Set(object obj, object value);
    }

    /// <summary>
    /// Products data manipualte helper
    /// </summary>
    public class Manipulation
    {
        #region constructor

        protected Manipulation()
        {
        }

        #endregion

        #region Getters

        protected class DelegateValueGetter : IPropertyValueGetter
        {
            GetPropertyValue _delegate;

            public DelegateValueGetter(GetPropertyValue theDelegate)
            {
                _delegate = theDelegate;
            }

            public object Get(object source)
            {
                return _delegate(source);
            }

        }

        protected class DynamicValueGetter : IPropertyValueGetter
        {
            string _name;

            public DynamicValueGetter(string name)
            {
                _name = name;
            }

            public object Get(object source)
            {
                return DataBinder.Eval(source, _name);
            }

        }

        protected class DelegateValueSetter : IPropertyValueSetter
        {
            SetPropertyValue _delegate;

            public DelegateValueSetter(SetPropertyValue theDelegate)
            {
                _delegate = theDelegate;
            }

            public void Set(object obj, object value)
            {
                _delegate(obj, value);
            }

        }

        protected class DynamicValueSetter : IPropertyValueSetter
        {
            string _name;

            public DynamicValueSetter(string name)
            {
                _name = name;
            }

            public void Set(object obj, object value)
            {
                // TODO
                throw new NotImplementedException();
            }

        }

        #endregion

        #region grouping


        /// <summary>
        /// group data by key returned GetKey delegate
        /// </summary>
        /// <param name="dataList"></param>
        /// <param name="GetKey"></param>
        /// <returns></returns>
        public static ICollection GroupData(ICollection dataList, GetPropertyValue GetKey)
        {
            return GroupData(dataList, new DelegateValueGetter(GetKey));
        }



        /// <summary>
        /// group data by name
        /// </summary>
        /// <param name="dataList"></param>
        /// <param name="name">property name</param>
        /// <returns></returns>
        public static ICollection GroupData(ICollection dataList, string name)
        {
            return GroupData(dataList, new DynamicValueGetter(name));
        }

        /// <summary>
        /// group data by key returned KeyGetter
        /// </summary>
        /// <param name="dataList"></param>
        /// <param name="KeyGetter"></param>
        /// <returns></returns>
        public static ICollection GroupData(System.Collections.ICollection dataList, IPropertyValueGetter KeyGetter)
        {
            ListDictionary sectionMap = new ListDictionary();
            foreach (object o in dataList)
            {
                object key = KeyGetter.Get(o);
                if (sectionMap[key] == null)
                {
                    sectionMap[key] = new ArrayList(4);
                }
                ((IList)sectionMap[key]).Add(o);
            }

            return sectionMap;
        }

        /// <summary>
        /// make tree structure from list structure
        /// </summary>
        /// <param name="list">source list</param>
        /// <param name="parentProperty">parent property getter</param>
        /// <param name="childsProperty"></param>
        /// <returns></returns>
        public static IList GroupByParent(ICollection list, IPropertyValueGetter parentProperty, IPropertyValueSetter childsProperty, IPropertyValueGetter idProperty)
        {
            IList ret = new ArrayList(list);
            Hashtable ids = new Hashtable();
            GroupingScope scope = new GroupingScope(childsProperty);
            foreach (object o in list)
            {
                ids[idProperty.Get(o)] = o;
            }
            foreach (object o in list)
            {
                object parentId = parentProperty.Get(o);
                if (ids.ContainsKey(parentId))
                {
                    object parent = ids[parentId];
                    // get childs list

                    // add to childs
                    IList childs = scope.GetChilds(parent);
                    childs.Add(o);
                    // remove from return list
                    ret.Remove(o);
                }
            }

            scope.AssignChilder();

            return ret;
        }

        private class GroupingScope
        {
            Hashtable _childred = new Hashtable();
            IPropertyValueSetter _childsProperty;

            public GroupingScope(IPropertyValueSetter childsProperty)
            {
                this._childsProperty = childsProperty;
            }

            public IList GetChilds(object o)
            {
                if (!_childred.ContainsKey(o))
                    _childred[o] = CreateList();
                return (IList)_childred[o];
            }

            public void AssignChilder()
            {
                foreach (DictionaryEntry entry in _childred)
                {
                    _childsProperty.Set(entry.Key, entry.Value);
                }
            }

            private IList CreateList()
            {
                return new ArrayList();
            }

        }


        public static IList GroupByParent(ICollection list, GetPropertyValue parentProperty, SetPropertyValue childsProperty, GetPropertyValue idProperty)
        {
            return GroupByParent(list, new DelegateValueGetter(parentProperty), new DelegateValueSetter(childsProperty), new DelegateValueGetter(idProperty));
        }

        #endregion

        #region Collections

        public static ArrayList CreateArrayList(object obj, ICollection collection)
        {
            ArrayList ret = new ArrayList(collection.Count + 1);
            ret.Add(obj);
            foreach (object o in collection)
            {
                ret.Add(o);
            }
            return ret;
        }

        public static ArrayList CreateArrayList(ICollection collection, params object[] objects)
        {
            ArrayList ret = new ArrayList(collection);
            foreach (object o in objects)
            {
                ret.Add(o);
            }
            return ret;
        }

        public static ArrayList CreateArrayList(params ICollection[] collections)
        {
            ArrayList ret = new ArrayList(collections.Length);
            foreach (ICollection c in collections)
            {
                foreach (object o in c)
                {
                    ret.Add(o);
                }
            }
            return ret;
        }

        #endregion
    }
}

